/*
** free.c for  in /home/alxevo/Documents/projets/malloc/malloc_norme
** 
** Made by Thibault Ravera
** Login   <ravera_t@epitech.net>
** 
** Started on  Fri Feb  3 22:03:41 2012 Thibault Ravera
** Last update Sun Feb  5 23:36:10 2012 Thibault Ravera
*/

#include	"malloc.h"

void		add_to_list(void *ptr);

int		check_in_data_range(void *p)
{
  t_data_range	*tmp;

  tmp = DATA_RANGE(head_heap_ori);
  while (tmp)
    {
      if (((tmp)->head + _MIN_CHUNK) != (tmp)->queue)
	{
	  if ((p >= ((tmp)->head + _MIN_CHUNK) && p < ((tmp)->queue - _MYSIZE_T)))
	    return (1);
	}
      tmp = tmp->next;
    }
  return (0);
}

void		concat_free_blocks(void *ptr)
{
  void		*begin;

  begin = ptr;
  ptr = (ptr - MEM2CHUNK(ptr)->prev_size);
  if (ptr)
    {
      MEM2CHUNK(ptr)->size += (MEM2CHUNK(begin)->size & ~PINUSE);
      MEM2CHUNK(begin)->size = 0;
      MEM2CHUNK(begin)->prev = 0;
      NCHUNKSIZE(ptr + (MEM2CHUNK(ptr)->size & ~PINUSE))->prev_size =
	(MEM2CHUNK(ptr)->size & ~PINUSE);
      NCHUNKSIZE(ptr + (MEM2CHUNK(ptr)->size & ~PINUSE))->size |= PINUSE;
    }
}

void		add_to_list(void *ptr)
{
  if (bins[_MYLIST])
    MEM2CHUNK(bins[_MYLIST])->next = ptr;
  NCHUNKSIZE(ptr + (MEM2CHUNK(ptr)->size & ~PINUSE))->size |= PINUSE;
  NCHUNKSIZE(ptr + (MEM2CHUNK(ptr)->size & ~PINUSE))->prev_size =
    (MEM2CHUNK(ptr)->size & ~PINUSE);
  MEM2CHUNK(ptr)->prev = bins[_MYLIST];
  MEM2CHUNK(ptr)->next = NULL;
  bins[_MYLIST] = ptr;
}

void		add_to_bins(void *ptr, int idx)
{
  if (bins[idx])
    MEM2CHUNK(bins[idx])->next = ptr;
  MEM2CHUNK(ptr)->next = NULL;
  MEM2CHUNK(ptr)->prev = bins[idx];
  bins[idx] = ptr;
}

void		free(void *ptr)
{
  pthread_mutex_lock(&lock_list);
  if (ptr == NULL)
    {
      pthread_mutex_unlock(&lock_list);
      return;
    }
  if (check_in_data_range(ptr) == 0)
    {
      pthread_mutex_unlock(&lock_list);
      return;
    }
  if ((MEM2CHUNK(ptr)->size & ~PINUSE) == 0)
    return;
  if (MEM2CHUNK(ptr)->size <= _MAXSIZE_BINS)
    add_to_bins(ptr, IDX(MEM2CHUNK(ptr)->size));
  else
    {
      if ((MEM2CHUNK(ptr)->size & PINUSE) &&
	  (MEM2CHUNK(ptr)->prev_size > _MAXSIZE_BINS))
      	concat_free_blocks(ptr);
      else
	add_to_list(ptr);
    }
  pthread_mutex_unlock(&lock_list);
}
